﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace QldtSdh.BLL
{
    using DAL;
    using DAL.Models;
    using Utils;

    class BizDaoTao
    {
        public static string LayThongTinTomTatLHP(HocKy hocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
            {
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return LayThongTinTomTatLHP(hocKy, db2); }
            }
            else
            {
                var st = new StringBuilder();
                // Lấy tổng số LHP đang tồn tại trong học kỳ
                var lstLopHocPhan = GetListLopHocPhan(hocKy, db);
                st.AppendFormat("Số lớp học phần: {0}\r\n", lstLopHocPhan.Count);

                // Lấy danh sách các lớp khoá-ngành đang trong kế hoạch đào tạo của học kỳ
                st.AppendFormat("Các lớp khoá-ngành trong kế hoạch đào tạo:\r\n");
                var lstLopKhoaNganhTrongKHDT = BizDaoTao.GetListLopKhoaNganhTrongKHDT(hocKy, db);
                foreach (var lopKhoaNganh in lstLopKhoaNganhTrongKHDT)
                    st.AppendFormat("  - Lớp {0}\r\n", lopKhoaNganh.TenLopKhoaNganh);
                return st.ToString();
            }
        }

        public static IList<LopHocPhan> GetListLopHocPhan(HocKy hocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListLopHocPhan(hocKy, db2); }
            else
            {
                var lstLopHocPhan = db.LopHocPhanDbSet.Where(e => e.MaHocKyGUID == hocKy.MaHocKyGUID).ToList();
                return lstLopHocPhan;
            }
        }

        /// <summary>
        /// Lấy danh sách các đơn vị có tham gia đào tạo trong học kỳ "hocKy".
        /// </summary>
        /// <param name="hocKy"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static IList<DonVi> GetListDonViDaoTaoTrongHocKy(HocKy hocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
            {
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListDonViDaoTaoTrongHocKy(hocKy, db2); }
            }
            else
            {
                var lstDonVi = db.LopHocPhanDbSet
                    .Include("HocPhan")
                    .Include("DonViPhuTrach")
                    .Where(e => e.MaHocKyGUID == hocKy.MaHocKyGUID)
                    .Select(e => e.HocPhan.DonVi)
                    .Distinct<DonVi>()
                    .OrderBy(e => e.TenDonVi)
                    .ToList();
                return lstDonVi;
            }
        }

        public static void TaoLopHocPhanTrongKHDT(HocKy hocKy, DateTime ngayBatDauDuKien, CEMS4UG_DHKHContext db = null,
            System.ComponentModel.ProgressChangedEventHandler reportHandler = null,
            System.ComponentModel.RunWorkerCompletedEventHandler summaryHandler = null
        )
        {
            if (db == null)
            {
                var db2 = CEMS4UG_DHKHContext.GetContext();
                //using (var db2 = CEMS4UG_DHKHContext.GetContext())
                {
                    TaoLopHocPhanTrongKHDT(hocKy, ngayBatDauDuKien, db2, reportHandler, summaryHandler);
                }
            }
            else
            {
                #region Tạo các LHP trong KHDT
                var bw = new System.ComponentModel.BackgroundWorker() { WorkerSupportsCancellation = true, WorkerReportsProgress = true };
                bw.DoWork += (oSender, oE) =>
                {
                    #region DoWork
                    // 0. Danh sách các lớp học phần trong học kỳ đang chọn
                    bw.ReportProgress(1, string.Format("1. Lấy danh sách lớp học phần hiện có trong KHĐT..."));
                    var maHocKyGUID = hocKy.MaHocKyGUID;
                    var lstLopHocPhan = db.LopHocPhanDbSet.Where(e => e.MaHocKyGUID == maHocKyGUID).ToList();
                    bw.ReportProgress(1, string.Format("có {0} lớp học phần\r\n", lstLopHocPhan.Count));

                    // 1. Lấy danh sách các lớp khoá ngành trong KHDT
                    bw.ReportProgress(2, string.Format("2. Lấy danh sách lớp khoá ngành trong KHĐT..."));
                    var lstLopKhoaNganh = GetListLopKhoaNganhTrongKHDT(hocKy, db);
                    bw.ReportProgress(2, string.Format("có {0} lớp khoá ngành\r\n", lstLopKhoaNganh.Count));

                    // 2. Ứng với mỗi lớp khoá ngành, suy ra tương ứng học kỳ trong KHDT -> danh sách học phần trong KHDT -> tạo LHP cho lớp khoá ngành này (nếu chưa tồn tại)
                    bw.ReportProgress(3, string.Format("3. Tạo lớp học phần...\r\n"));
                    var dict = new Dictionary<string, List<ChuongTrinhDaoTao_HocPhan>>();
                    var lstLopHocPhanTaoMoi = new List<LopHocPhan>();
                    foreach (var lopKhoaNganh in lstLopKhoaNganh)
                    {
                        //System.Threading.Thread.Sleep(1000);
                        var idxHocKyTrongChuongTrinhDaoTao = (hocKy.NamHoc - lopKhoaNganh.KhoaHoc_NganhDaoTao.KhoaHoc.NamTuyenSinh) * 2 + hocKy.SoThuTuHocKy;
                        var chuongTrinhDaoTao = lopKhoaNganh.KhoaHoc_NganhDaoTao.ChuongTrinhDaoTao;
                        #region List<ChuongTrinhDaoTao_HocPhan> lstCTDT_HocPhan = danh sách học phần trong học kỳ này của CTDT;
                        List<ChuongTrinhDaoTao_HocPhan> lstCTDT_HocPhan = null;
                        string key = string.Format("{0}.{1}", chuongTrinhDaoTao.MaChuongTrinhDaoTaoGUID, idxHocKyTrongChuongTrinhDaoTao);
                        if (dict.ContainsKey(key) == false)
                        {
                            lstCTDT_HocPhan = db.ChuongTrinhDaoTao_HocPhanDbSet.Include("HocPhan")
                                .Where(e =>
                                    e.HocKy == idxHocKyTrongChuongTrinhDaoTao &&
                                    e.MaChuongTrinhDaoTaoGUID == chuongTrinhDaoTao.MaChuongTrinhDaoTaoGUID)
                                .ToList();
                            dict.Add(key, lstCTDT_HocPhan);
                        }
                        else
                            lstCTDT_HocPhan = dict[key];
                        #endregion

                        bw.ReportProgress(4, string.Format("\tLớp khoá ngành {0} (Học kỳ {1}: {2} học phần trong CTĐT)\r\n", lopKhoaNganh.TenLopKhoaNganh, idxHocKyTrongChuongTrinhDaoTao, lstCTDT_HocPhan.Count));
                        var maLopKhoaNganh = lopKhoaNganh.MaLopKhoaNganhGUID;
                        var tenLopKhoaNganh = lopKhoaNganh.TenLopKhoaNganh;
                        foreach (var hpCTDT in lstCTDT_HocPhan)
                        {
                            //System.Threading.Thread.Sleep(100);
                            var hocPhan = hpCTDT.HocPhan;
                            #region bool daCoLop = đã có Lớp học phần mở cho lớp khoá ngành này?
                            bool daCoLop = false;
                            var maHocPhan = hpCTDT.MaHocPhan;
                            foreach (var lhp in lstLopHocPhan)
                                if (lhp.MaLopKhoaNganhThamChieu == maLopKhoaNganh && lhp.MaHocPhanGUID == maHocPhan)
                                {
                                    daCoLop = true;
                                    break;
                                }
                            #endregion
                            if (daCoLop == false)
                            {
                                bw.ReportProgress(4, string.Format("\t\tHọc phần [{0}] {1}...", hocPhan.MaHocPhan, hocPhan.TenHocPhan));
                                #region var lopHocPhan = ...;
                                // Tìm stt nhỏ nhất còn dùng làm mã cho LHP được
                                string prefix = string.Format("{0}.{1}.{2}.",
                                    hocKy.NamHoc, hocKy.SoThuTuHocKy, hocPhan.MaHocPhan);
                                var idx = 1;
                                string maLopHocPhan = "";
                                while (true)
                                {
                                    maLopHocPhan = prefix + StringUtils.Thousandize(idx);
                                    if (BizDaoTao.DaTonTaiMaLopHocPhan(maLopHocPhan, db))
                                    {
                                        idx++;
                                        if (idx >= 1000)
                                            throw new Exception("Có lỗi bất thường. Không thể thử tạo được 1000 lớp học phần trên cơ sở dữ liệu.");
                                    }
                                    else
                                        break;
                                }
                                if (string.IsNullOrEmpty(maLopHocPhan))
                                    throw new Exception("Có lỗi bất thường. Không thể tạo ra mã lớp học phần được.");

                                var lopHocPhan = new LopHocPhan()
                                    {
                                        MaHocKyGUID = maHocKyGUID,
                                        MaLopHocPhanGUID =
                                            //System.Guid.NewGuid().ToString(),
                                            //string.Format("{0}.{1}.{2}.{3}", hocKy.NamHoc, hocKy.SoThuTuHocKy, hocPhan.MaHocPhan, lopKhoaNganh.KhoaHoc_NganhDaoTao.NganhDaoTao.MaSoNganhDaoTao),
                                            maLopHocPhan,
                                        MaHocPhanGUID = hpCTDT.MaHocPhan,
                                        MaLopKhoaNganhThamChieu = maLopKhoaNganh,
                                        TenLopHocPhan = string.Format("{0} - {1}", hocPhan.TenHocPhan, tenLopKhoaNganh),
                                        HinhThucHoc = hocPhan.HinhThucHoc,
                                        HinhThucThi = hocPhan.HinhThucThi,
                                        ThoiGianThi = hocPhan.SoTinChi * 45,
                                        HeSoDiemQTHT = hocPhan.HeSoDiemQTHT,
                                        NgayBatDauDuKien = ngayBatDauDuKien
                                    };
                                #endregion
                                //bw.ReportProgress(4, string.Format("\t\tLớp học phần [{0}] - length={1}\r\n", lopHocPhan.MaLopHocPhanGUID, lopHocPhan.MaLopHocPhanGUID.Length));

                                // Danh sách học viên cho lopHocPhan này
                                var lstHocVien = db.HocVienDbSet
                                    .Where(e => e.MaLopKhoaNganhGUID == maLopKhoaNganh).ToList();

                                #region var lstMaHocVienDaDangKyHP = danh sách NaHocVien đã đăng ký học phần
                                var lstMaHocVienDaDangKyHP = db.LopHocPhan_HocVienDbSet.Include("LopHocPhan")
                                                        .Where(e => e.LopHocPhan.MaHocPhanGUID == hpCTDT.MaHocPhan)
                                                        .Select(e => e.MaHocVien)
                                                        .ToList();
                                lstMaHocVienDaDangKyHP.Sort();
                                #endregion

                                #region Bổ sung các học viên cần thiết vào lopHocPhan;
                                var nSoHocVienBoSung = 0;
                                var maLopHocPhanMoi = lopHocPhan.MaLopHocPhanGUID;
                                foreach (var hocVien in lstHocVien)
                                {
                                    var lanHocHocPhanCuaHocVien = 1; // TODO: Tính lần học HocPhan này của học viên hocVien
                                    bool hocVienHocThayThe = false;
                                    string maHocPhanGUID_ThayThe = null;
                                    if (lstMaHocVienDaDangKyHP.Contains(hocVien.MaHocVien) == false)
                                    {
                                        nSoHocVienBoSung++;
                                        var recDangKyLHP = new LopHocPhan_HocVien()
                                        {
                                            MaLopHocPhanGUID = maLopHocPhanMoi,
                                            MaHocVien = hocVien.MaHocVien,
                                            LanHoc = lanHocHocPhanCuaHocVien,
                                            HocThayThe = hocVienHocThayThe,
                                            MaHocPhanGUID_ThayThe = maHocPhanGUID_ThayThe
                                        };
                                        db.LopHocPhan_HocVienDbSet.Add(recDangKyLHP);
                                    }
                                }
                                db.LopHocPhanDbSet.Add(lopHocPhan);
                                BizNhatKyHoatDong.LogAndCommitInsert<LopHocPhan>(lopHocPhan, lopHocPhan.MaLopHocPhanGUID, LOAIDOITUONG.LỚP_HỌC_PHẦN, db);
                                bw.ReportProgress(4, string.Format("bổ sung {0}/{1} học viên\r\n", nSoHocVienBoSung, lstHocVien.Count));
                                #endregion

                                lstLopHocPhanTaoMoi.Add(lopHocPhan);
                            }
                            else
                                bw.ReportProgress(4, string.Format("\t\tHọc phần [{0}] {1}... đã tồn tại.\r\n", hocPhan.MaHocPhan, hocPhan.TenHocPhan));
                        }
                    }

                    // 3. Commit
                    //BizNhatKyHoatDong.LogAndCommitInsert<List<LopHocPhan>>(lstLopHocPhanTaoMoi, lstLopHocPhanTaoMoi.GetHashCode().ToString(), LOAIDOITUONG.LỚP_HỌC_PHẦN, db);
                    bw.ReportProgress(5, string.Format("Đã tạo mới được {0} lớp học phần\r\n", lstLopHocPhanTaoMoi.Count));
                    #endregion
                };
                bw.ProgressChanged += (oSender, oE) => { if (reportHandler != null) reportHandler(oSender, oE); };
                bw.RunWorkerCompleted += (oSender, oE) =>
                {
                    db.Dispose();
                    if (summaryHandler != null) summaryHandler(oSender, oE);
                };
                bw.RunWorkerAsync();
                #endregion
            }
        }

        /// <summary>
        /// Cho biết có tồn tại lớp học phần có mã "maLopHocPhan" hay không?
        /// </summary>
        /// <param name="maLopHocPhan"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static bool DaTonTaiMaLopHocPhan(string maLopHocPhan, CEMS4UG_DHKHContext db)
        {
            if (db == null)
            {
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return DaTonTaiMaLopHocPhan(maLopHocPhan, db2); }
            }
            else
            {
                var oLopHocPHan = db.LopHocPhanDbSet.Where(e => e.MaLopHocPhanGUID == maLopHocPhan).FirstOrDefault();
                return oLopHocPHan != null;
            }
        }

        /// <summary>
        /// Lấy danh sách KhoaHoc_NganhDaoTao trong 1 Khoá học
        /// Có bao gồm NganhDaoTao
        /// </summary>
        /// <param name="khoaHoc"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<KhoaHoc_NganhDaoTao> GetListKhoaHoc_NganhDaoTaoTrongKhoaHoc(KhoaHoc khoaHoc, CEMS4UG_DHKHContext db)
        {
            if (khoaHoc == null)
                return null;

            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListKhoaHoc_NganhDaoTaoTrongKhoaHoc(khoaHoc, db2); }
            else
            {
                var lstKhoaNganh = db.KhoaHoc_NganhDaoTaoDbSet
                    .Include("NganhDaoTao")
                    .Where(e => e.MaKhoaHocGUID == khoaHoc.MaKhoaHocGUID)
                    .OrderBy(e => e.NganhDaoTao.MaNganhDaoTao)
                    .ToList();
                return lstKhoaNganh;
            }
        }

        //internal static List<CoSoDaoTao> GetListCoSoDaoTaoTrongKhoaHoc(KhoaHoc_NganhDaoTao khoaHoc_NganhDaoTao, CEMS4UG_DHKHContext db)
        //{
        //    if (khoaHoc_NganhDaoTao == null)
        //        return null;
        //    if (db == null)
        //        using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListCoSoDaoTaoTrongKhoaHoc(khoaHoc_NganhDaoTao, db2); }
        //    else
        //    {
        //        var lst = db.LopKhoaNganhDbSet
        //            .Where(e => e.MaDaoTaoKhoaNganhGUID == khoaHoc_NganhDaoTao.MaDaoTaoKhoaNganhGUID)
        //            .Select(e => e.CoSoDaoTao)
        //            .ToList();
        //        return lst;
        //    }
        //}

        /// <summary>
        /// Lấy danh sách lớp khoá-ngành trong KHĐT (sắp xếp theo năm tuyển sinh của các lớp khoá-ngành). Các chi tiết kèm theo
        /// KhoaHoc
        /// ChuongTrinhDaoTao
        /// NganhDaoTao
        /// </summary>
        /// <param name="hocKy"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static IList<LopKhoaNganh> GetListLopKhoaNganhTrongKHDT(HocKy hocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
            {
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListLopKhoaNganhTrongKHDT(hocKy, db2); }
            }
            else
            {
                var namHocHienTai = hocKy.NamHoc;
                var lst = db.KhoaHoc_NganhDaoTaoDbSet
                    .Include("KhoaHoc")
                    .Include("ChuongTrinhDaoTao")
                    //.Include("ChuongTrinhDaoTao_HocPhan")
                    //.Include("HocPhan")
                    .Include("NganhDaoTao")
                    .Where(e =>
                        e.ChuongTrinhDaoTao.SoHocKyDaoTao / 2 + e.KhoaHoc.NamTuyenSinh > namHocHienTai &&
                        e.KhoaHoc.NamTuyenSinh <= namHocHienTai)
                    .OrderBy(e => e.KhoaHoc.NamTuyenSinh)
                    .ThenBy(e => e.NganhDaoTao.MaNganhDaoTao)
                    .ToList();
                var lstLopKhoaNganh = new List<LopKhoaNganh>();
                foreach (var e in lst)
                    lstLopKhoaNganh.AddRange(e.ListLopKhoaNganh.OrderBy(x => x.TenLopKhoaNganh));
                return lstLopKhoaNganh;
            }
        }

        /// <summary>
        /// Lấy danh sách các lớp khoá-ngành của khoá "khoaHoc" trong học kỳ "hocKy" thuộc cơ sở đào tạo "coSoDaoTao"
        /// </summary>
        /// <param name="khoaHoc"></param>
        /// <param name="hocKy"></param>
        /// <param name="coSoDaoTao"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<LopKhoaNganh> GetListLopKhoaNganh(KhoaHoc khoaHoc, HocKy hocKy,
            CoSoDaoTao coSoDaoTao, CEMS4UG_DHKHContext db = null)
        {
            if (khoaHoc == null || coSoDaoTao == null || hocKy == null)
                return null;
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListLopKhoaNganh(khoaHoc, hocKy, coSoDaoTao, db2); }
            else
            {
                //System.Windows.Forms.MessageBox.Show(
                //    string.Format("Khoá học: {0}\nHọc kỳ: {1}\nCơ sở đào tạo:{2}",
                //    khoaHoc.MaKhoaHocGUID, hocKy.MaHocKyGUID, coSoDaoTao.TenCoSoDaoTao));
                var lstMaDaoTaoKhoaNganhGUID = db.KhoaHoc_NganhDaoTaoDbSet
                    .Include("KhoaHoc")
                    .Where(e =>
                        e.MaKhoaHocGUID == khoaHoc.MaKhoaHocGUID &&
                            //e.KhoaHoc.NamTuyenSinh  <= hocKy.NamHoc &&
                        hocKy.NamHoc <= e.KhoaHoc.NamTuyenSinh + 2)
                    .Select(e => e.MaDaoTaoKhoaNganhGUID)
                    .ToList();
                //System.Windows.Forms.MessageBox.Show(lstMaDaoTaoKhoaNganhGUID.Count.ToString() + " mã đào tạo khoá-ngành");

                var lst1 = GetListLopKhoaNganhTrongKHDT(hocKy, db);
                var lst =
                    //db.LopKhoaNganhDbSet
                    lst1
                    .Where(e =>
                        e.MaCoSoDaoTaoGUID == coSoDaoTao.MaCoSoDaoTaoGUID &&
                        lstMaDaoTaoKhoaNganhGUID.Contains(e.MaDaoTaoKhoaNganhGUID))
                    .OrderBy(e => e.TenLopKhoaNganh)
                    .ToList();
                //System.Windows.Forms.MessageBox.Show(lst.Count.ToString() + " lớp khoá ngành");
                return lst;
            }
        }

        /// <summary>
        /// Lấy danh sách lớp khoá-ngành trong học kỳ "hocKy" tại cơ sở đào tạo "coSoDaoTao"
        /// </summary>
        /// <param name="hocKy"></param>
        /// <param name="coSoDaoTao"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<LopKhoaNganh> GetListLopKhoaNganh(HocKy hocKy,
            CoSoDaoTao coSoDaoTao, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) { return GetListLopKhoaNganh(hocKy, coSoDaoTao, db2); }
            else
            {
                var lstMaDaoTaoKhoaNganhGUID = db.KhoaHoc_NganhDaoTaoDbSet
                    .Include("KhoaHoc")
                    .Where(e =>
                        hocKy.NamHoc <= e.KhoaHoc.NamTuyenSinh + 2)
                    .Select(e => e.MaDaoTaoKhoaNganhGUID)
                    .ToList();

                var lst1 = GetListLopKhoaNganhTrongKHDT(hocKy, db);
                var lst = lst1
                    .Where(e =>
                        e.MaCoSoDaoTaoGUID == coSoDaoTao.MaCoSoDaoTaoGUID &&
                        lstMaDaoTaoKhoaNganhGUID.Contains(e.MaDaoTaoKhoaNganhGUID))
                    .OrderBy(e => e.TenLopKhoaNganh)
                    .ToList();
                return lst;
            }
        }

        /// <summary>
        /// Lấy năm bắt đầu đào tạo của lớp khoá ngành == năm tuyển sinh
        /// </summary>
        /// <param name="lopKhoaNganh"></param>
        /// <returns></returns>
        internal static int getNamBatDauDaoTao(LopKhoaNganh lopKhoaNganh, CEMS4UG_DHKHContext db)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) return getNamBatDauDaoTao(lopKhoaNganh, db2);
            else
            {
                if (lopKhoaNganh.KhoaHoc_NganhDaoTao == null)
                {
                    var khoaHocNganhDaoTao = db.KhoaHoc_NganhDaoTaoDbSet.Where(e => e.MaDaoTaoKhoaNganhGUID == lopKhoaNganh.MaDaoTaoKhoaNganhGUID).FirstOrDefault();
                    if (khoaHocNganhDaoTao == null)
                        throw new Exception("Không lấy được thông tin Khoá học - Ngành đào tạo");
                    return db.KhoaHoc_NganhDaoTaoDbSet.Include("KhoaHoc")
                        .Where(e => e.KhoaHoc.MaKhoaHocGUID == khoaHocNganhDaoTao.MaKhoaHocGUID)
                        .Select(e => e.KhoaHoc.NamTuyenSinh)
                        .FirstOrDefault();
                }
                else
                    return db.KhoaHoc_NganhDaoTaoDbSet.Include("KhoaHoc")
                        .Where(e => e.KhoaHoc.MaKhoaHocGUID == lopKhoaNganh._MaKhoaHocGUID)
                        .Select(e => e.KhoaHoc.NamTuyenSinh)
                        .FirstOrDefault();
            }
        }

        /// <summary>
        /// Lấy danh sách các học phần trong chương trình đào tạo mà dành cho lớp khoá ngành "lopKhoaNganh" ở học kỳ "hocKy"
        /// </summary>
        /// <param name="hocKy"></param>
        /// <param name="lopKhoaNganh"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<ChuongTrinhDaoTao_HocPhan> getListHocPhanTuChonTrongCTDT(HocKy hocKy, LopKhoaNganh
            lopKhoaNganh, bool chiLayHocPhanKhongCoTrongKHDT, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) return getListHocPhanTuChonTrongCTDT(hocKy, lopKhoaNganh, chiLayHocPhanKhongCoTrongKHDT, db2);
            else
            {
                var hocKyTrongCTDT = (hocKy.NamHoc - getNamBatDauDaoTao(lopKhoaNganh, db)) * 2 + hocKy.SoThuTuHocKy;
                var khoa_nganhDaoTao = db.KhoaHoc_NganhDaoTaoDbSet
                    .Where(e => e.MaDaoTaoKhoaNganhGUID == lopKhoaNganh.MaDaoTaoKhoaNganhGUID).FirstOrDefault();
                if (khoa_nganhDaoTao == null)
                    throw new Exception("Không lấy được thông tin khoá-ngành đào tạo");
                //var ctdt = db.ChuongTrinhDaoTaoDbSet
                //    .Where(e => e.MaChuongTrinhDaoTaoGUID == khoa_nganhDaoTao.MaChuongTrinhDaoTaoGUID).FirstOrDefault();
                var lstHocPhanTrongKHDT = new List<string>();
                if (chiLayHocPhanKhongCoTrongKHDT)
                    lstHocPhanTrongKHDT = db.KeHoachDaoTaoDbSet
                        .Where(e => e.MaHocKyGUID == hocKy.MaHocKyGUID && e.MaLopKhoaNganhGUID == lopKhoaNganh.MaLopKhoaNganhGUID)
                        .Select(e => e.MaHocPhanGUID)
                        .ToList();

                var lstHocPhanTrongCTDT = db.ChuongTrinhDaoTao_HocPhanDbSet.Include("HocPhan")
                    .Where(e =>
                        e.MaChuongTrinhDaoTaoGUID == khoa_nganhDaoTao.MaChuongTrinhDaoTaoGUID &&
                        e.HocKy == hocKyTrongCTDT &&
                        !lstHocPhanTrongKHDT.Contains(e.MaHocPhan) &&
                        e.LaHocPhanBatBuoc == false)
                    .OrderBy(e => e.HocPhan.TenHocPhan)
                    .ToList();
                return lstHocPhanTrongCTDT;
            }

        }

        /// <summary>
        /// Lấy danh sách học phần dự kiến mở
        /// </summary>
        /// <param name="hocKy"></param>
        /// <param name="lopKhoaNganh"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<ChuongTrinhDaoTao_HocPhan> getListHocPhanTrongKHDT(HocKy hocKy,
            LopKhoaNganh lopKhoaNganh, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) return getListHocPhanTrongKHDT(hocKy, lopKhoaNganh, db2);
            else
            {
                var lstMaHocPhan =
                    db.KeHoachDaoTaoDbSet.Where(e => e.MaHocKyGUID == hocKy.MaHocKyGUID && e.MaLopKhoaNganhGUID == lopKhoaNganh.MaLopKhoaNganhGUID).Select(e => e.MaHocPhanGUID).ToList();
                //db.LopHocPhanDbSet.Where(e => e.HocKy.MaHocKyGUID == hocKy.MaHocKyGUID).Select(e => e.MaHocPhanGUID).Distinct().ToList();
                var hocKyTrongCTDT = (hocKy.NamHoc - getNamBatDauDaoTao(lopKhoaNganh, db)) * 2 + hocKy.SoThuTuHocKy;
                var khoa_nganhDaoTao = db.KhoaHoc_NganhDaoTaoDbSet
                    .Where(e => e.MaDaoTaoKhoaNganhGUID == lopKhoaNganh.MaDaoTaoKhoaNganhGUID).FirstOrDefault();
                if (khoa_nganhDaoTao == null)
                    throw new Exception("Không lấy được thông tin khoá-ngành đào tạo");
                var lstHocPhanTrongKHDT = db.ChuongTrinhDaoTao_HocPhanDbSet.Include("HocPhan")
                    .Where(e =>
                        e.MaChuongTrinhDaoTaoGUID == khoa_nganhDaoTao.MaChuongTrinhDaoTaoGUID &&
                        e.HocKy == hocKyTrongCTDT &&
                        (e.LaHocPhanBatBuoc || lstMaHocPhan.Contains(e.MaHocPhan)))
                    .OrderByDescending(e => e.LaHocPhanBatBuoc)
                    .ThenBy(e => e.HocPhan.TenHocPhan)
                    .ToList();
                return lstHocPhanTrongKHDT;
            }
        }

        /// <summary>
        /// Bổ sung kế hoạch đào tạo của lớp khoá-ngành với danh sách các học phần
        /// </summary>
        /// <param name="lopKhoaNganh"></param>
        /// <param name="hocKy"></param>
        /// <param name="lstMaHocPhan"></param>
        /// <param name="db"></param>
        internal static void BoSungKHDTChoLopKhoaNganh(LopKhoaNganh lopKhoaNganh, HocKy hocKy,
            List<string> lstMaHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) BoSungKHDTChoLopKhoaNganh(lopKhoaNganh, hocKy, lstMaHocPhan, db2);
            else
            {
                using (var trans = db.Database.BeginTransaction())
                {
                    try
                    {
                        var lst = new List<KeHoachDaoTao>();
                        foreach (var maHocPhan in lstMaHocPhan)
                        {
                            var x = new KeHoachDaoTao()
                            {
                                MaHocKyGUID = hocKy.MaHocKyGUID,
                                MaLopKhoaNganhGUID = lopKhoaNganh.MaLopKhoaNganhGUID,
                                MaHocPhanGUID = maHocPhan
                            };
                            lst.Add(x);
                            db.KeHoachDaoTaoDbSet.Add(x);
                            BizNhatKyHoatDong.LogAndCommitInsert2(x, x._MaKeHoachDaoTaoGUID, LOAIDOITUONG.KẾ_HOẠCH_ĐÀO_TẠO, db);
                        }

                        trans.Commit();
                    }
                    catch (Exception exc)
                    {
                        trans.Rollback();
                        throw exc;
                    }
                }
            }
        }

        internal static void LoaiBoKHDTHocPhanChoLopKhoaNganh(LopKhoaNganh lopKhoaNganh, HocKy hocKy,
            List<string> lstMaHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    LoaiBoKHDTHocPhanChoLopKhoaNganh(lopKhoaNganh, hocKy, lstMaHocPhan, db2);
            else
            {
                using (var trans = db.Database.BeginTransaction())
                {
                    try
                    {
                        var lst = new List<KeHoachDaoTao>();
                        foreach (var maHocPhan in lstMaHocPhan)
                        {
                            var x = db.KeHoachDaoTaoDbSet
                                .Where(e =>
                                    e.MaHocKyGUID == hocKy.MaHocKyGUID &&
                                    e.MaHocPhanGUID == maHocPhan && e
                                    .MaLopKhoaNganhGUID == lopKhoaNganh.MaLopKhoaNganhGUID).FirstOrDefault();
                            if (x == null)
                                throw new Exception(string.Format("Học phần {0} không còn tồn tại trong kế hoạch đào tạo ở học kỳ {1} của lớp khoá-ngành {2}",
                                    maHocPhan, hocKy.TenHocKyDayDu, lopKhoaNganh.TenLopKhoaNganh));
                            lst.Add(x);
                            db.KeHoachDaoTaoDbSet.Remove(x);
                            BizNhatKyHoatDong.LogAndCommitDelete2(x, x._MaKeHoachDaoTaoGUID, LOAIDOITUONG.KẾ_HOẠCH_ĐÀO_TẠO, db);
                        }

                        trans.Commit();
                    }
                    catch (Exception exc)
                    {
                        trans.Rollback();
                        throw exc;
                    }
                }
            }
        }

        #region TẠO LỚP HỌC PHẦN TRONG KẾ HOẠCH ĐÀO TẠO
        /// <summary>
        /// Lấy tình trạng mở lớp học phần của các học phần trong KHDT của 1 lớp khoá-ngành trong học kỳ cho trước
        /// </summary>
        /// <param name="lopKhoaNganh"></param>
        /// <param name="_HocKy"></param>
        /// <returns></returns>
        internal static IList<KeHoachDaoTao> GetListTinhTrangMoLopHocPhanTrongKHDT(LopKhoaNganh lopKhoaNganh,
            HocKy hocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetListTinhTrangMoLopHocPhanTrongKHDT(lopKhoaNganh, hocKy, db2);
            else
            {

                // danh sách các mã học phần đã được mở lớp
                var lstMaHocPhan = db.LopHocPhanDbSet.Where(e => e.MaHocKyGUID == hocKy.MaHocKyGUID && e.MaLopKhoaNganhThamChieu == lopKhoaNganh.MaLopKhoaNganhGUID).Select(e => e.MaHocPhanGUID).ToList();

                // lst = danh sách các học phần (tự chọn) trong KHDT
                var lst = db.KeHoachDaoTaoDbSet.Include("HocPhan")
                    .Where(e => e.MaHocKyGUID == hocKy.MaHocKyGUID && e.MaLopKhoaNganhGUID == lopKhoaNganh.MaLopKhoaNganhGUID)
                    .ToList();

                #region lst = lst + danh sách các học phần bắt buộc của lớp khoá-ngành (Do KHDT chỉ chứa các học phần không bắt buộc)
                var hocKyTrongCTDT = (hocKy.NamHoc - getNamBatDauDaoTao(lopKhoaNganh, db)) * 2 + hocKy.SoThuTuHocKy;
                var khoa_nganhDaoTao = db.KhoaHoc_NganhDaoTaoDbSet
                    .Where(e => e.MaDaoTaoKhoaNganhGUID == lopKhoaNganh.MaDaoTaoKhoaNganhGUID).FirstOrDefault();
                if (khoa_nganhDaoTao == null)
                    throw new Exception("Không lấy được thông tin khoá-ngành đào tạo");
                var lstHocPhanBatBuocTrongKHDT = db.ChuongTrinhDaoTao_HocPhanDbSet.Include("HocPhan")
                    .Where(e =>
                        e.MaChuongTrinhDaoTaoGUID == khoa_nganhDaoTao.MaChuongTrinhDaoTaoGUID &&
                        e.HocKy == hocKyTrongCTDT &&
                        (e.LaHocPhanBatBuoc))
                    //.OrderByDescending(e => e.LaHocPhanBatBuoc)
                    .OrderBy(e => e.HocPhan.TenHocPhan)
                    .ToList();
                foreach (var hocPhan in lstHocPhanBatBuocTrongKHDT)
                    lst.Add(new KeHoachDaoTao() { MaHocKyGUID = hocKy.MaHocKyGUID, MaHocPhanGUID = hocPhan.MaHocPhan, HocPhan = hocPhan.HocPhan, MaLopKhoaNganhGUID = lopKhoaNganh.MaLopKhoaNganhGUID });
                #endregion

                foreach (var x in lst)
                    x._TrangThai = lstMaHocPhan.Contains(x.MaHocPhanGUID) ? "Đã tồn tại" : "";

                return new Utils.MySortableBindingList<KeHoachDaoTao>(lst);
            }
        }

        internal static List<KeHoachDaoTao> GetListHocPhanTrongKHDTChuaDuocMoLopHocPhan(LopKhoaNganh LOPKHOANGANH,
            CoSoDaoTao coSoDaoTao, HocKy hocKy, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext()) return GetListHocPhanTrongKHDTChuaDuocMoLopHocPhan(LOPKHOANGANH, coSoDaoTao, hocKy, db2);
            else
            {
                IList<LopKhoaNganh> lstLopKhoaNganh = null;
                if (LOPKHOANGANH == null)
                    lstLopKhoaNganh = GetListLopKhoaNganhTrongKHDT(hocKy, db);
                else
                    lstLopKhoaNganh = new List<LopKhoaNganh>() { LOPKHOANGANH };

                List<KeHoachDaoTao> lst = new List<KeHoachDaoTao>();
                foreach (var lopKN in lstLopKhoaNganh)
                    if (lopKN.MaCoSoDaoTaoGUID == coSoDaoTao.MaCoSoDaoTaoGUID)
                    {
                        // danh sách mã học phần được mở cho lớp khoá ngành
                        var lstMaHocPhanDaTonTai = db.LopHocPhanDbSet.Where(e =>
                            e.MaHocKyGUID == hocKy.MaHocKyGUID &&
                            e.MaLopKhoaNganhThamChieu == lopKN.MaLopKhoaNganhGUID).Select(e => e.MaHocPhanGUID).ToList();

                        // danh sách các học phần tự chọn trong khdt & chưa được mở lớp
                        var lstKHDT = db.KeHoachDaoTaoDbSet.Include("HocPhan").Include("LopKhoaNganh")
                            .Where(e =>
                                e.MaHocKyGUID == hocKy.MaHocKyGUID &&
                                e.MaLopKhoaNganhGUID == lopKN.MaLopKhoaNganhGUID &&
                                lstMaHocPhanDaTonTai.Contains(e.MaHocPhanGUID) == false).ToList();
                        lst.AddRange(lstKHDT);

                        #region danh sách các học phần bắt buộc trong CTDT của lớp khoá-ngành
                        var hocKyTrongCTDT = (hocKy.NamHoc - getNamBatDauDaoTao(lopKN, db: null)) * 2 + hocKy.SoThuTuHocKy;
                        var khoa_nganhDaoTao = db.KhoaHoc_NganhDaoTaoDbSet
                            .Where(e => e.MaDaoTaoKhoaNganhGUID == lopKN.MaDaoTaoKhoaNganhGUID).FirstOrDefault();
                        if (khoa_nganhDaoTao == null)
                            throw new Exception("Không lấy được thông tin khoá-ngành đào tạo");
                        var lstHocPhanBatBuocTrongKHDT = db.ChuongTrinhDaoTao_HocPhanDbSet.Include("HocPhan")
                            .Where(e =>
                                e.MaChuongTrinhDaoTaoGUID == khoa_nganhDaoTao.MaChuongTrinhDaoTaoGUID &&
                                e.HocKy == hocKyTrongCTDT &&
                                (e.LaHocPhanBatBuoc))
                            .OrderByDescending(e => e.LaHocPhanBatBuoc)
                            .ThenBy(e => e.HocPhan.TenHocPhan)
                            .ToList();
                        foreach (var hocPhan in lstHocPhanBatBuocTrongKHDT)
                            if (lstMaHocPhanDaTonTai.Contains(hocPhan.MaHocPhan) == false)
                                lst.Add(new KeHoachDaoTao()
                                {
                                    MaHocKyGUID = hocKy.MaHocKyGUID,
                                    MaHocPhanGUID = hocPhan.MaHocPhan,
                                    HocPhan = hocPhan.HocPhan,
                                    MaLopKhoaNganhGUID = lopKN.MaLopKhoaNganhGUID,
                                    LopKhoaNganh = lopKN
                                });
                        #endregion
                    }
                return lst;
            }
        }

        internal static DateTime getNgayBatDauDuKien(HocKy hocKy, CoSoDaoTao coSoDaoTao)
        {
            return DateTime.Now;
        }

        internal static int TaoLopHocPhan(List<KeHoachDaoTao> lstHocPhanTrongKHDT, HocKy hocKy,
            CoSoDaoTao coSoDaoTao, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return TaoLopHocPhan(lstHocPhanTrongKHDT, hocKy, coSoDaoTao, db2);
            else
            {
                using (var trans = db.Database.BeginTransaction())
                {
                    try
                    {
                        var lstAdded = new List<LopHocPhan>();
                        var lstMaLopHocPhanDaTao = new List<string>();
                        foreach (var hocPhan in lstHocPhanTrongKHDT)
                        {
                            #region var lopHocPhan = ...;
                            // Tìm stt nhỏ nhất còn dùng làm mã cho LHP được
                            string prefix = string.Format("{0}.{1}.{2}.",
                                hocKy.NamHoc, hocKy.SoThuTuHocKy, hocPhan._MaHocPhan);
                            #region string maLopHocPhan = tạo mã lớp học phần tự động;
                            string maLopHocPhan = "";
                            var idx = 1;
                            while (true)
                            {
                                maLopHocPhan = prefix + StringUtils.Thousandize(idx);
                                if (BizDaoTao.DaTonTaiMaLopHocPhan(maLopHocPhan, db) || lstMaLopHocPhanDaTao.Contains(maLopHocPhan))
                                {
                                    idx++;
                                    if (idx >= 1000)
                                        throw new Exception("Có lỗi bất thường. Không thể thử tạo được 1000 lớp học phần trên cơ sở dữ liệu.");
                                }
                                else
                                    break;
                            }
                            #endregion
                            if (string.IsNullOrEmpty(maLopHocPhan))
                                throw new Exception("Có lỗi bất thường. Không thể tạo ra mã lớp học phần được.");
                            lstMaLopHocPhanDaTao.Add(maLopHocPhan);

                            #region var lopHocPhan = ...;
                            var lopHocPhan = new LopHocPhan()
                                        {
                                            MaHocKyGUID = hocKy.MaHocKyGUID,
                                            MaLopHocPhanGUID =
                                                //System.Guid.NewGuid().ToString(),
                                                //string.Format("{0}.{1}.{2}.{3}", hocKy.NamHoc, hocKy.SoThuTuHocKy, hocPhan.MaHocPhan, lopKhoaNganh.KhoaHoc_NganhDaoTao.NganhDaoTao.MaSoNganhDaoTao),
                                                maLopHocPhan,
                                            MaHocPhanGUID = hocPhan.MaHocPhanGUID,
                                            MaLopKhoaNganhThamChieu = hocPhan.MaLopKhoaNganhGUID,
                                            TenLopHocPhan = string.Format("{0} - {1}", hocPhan.HocPhan.TenHocPhan, hocPhan.LopKhoaNganh.TenLopKhoaNganh),
                                            HinhThucHoc = hocPhan.HocPhan.HinhThucHoc,
                                            HinhThucThi = hocPhan.HocPhan.HinhThucThi,
                                            ThoiGianThi = hocPhan.HocPhan.SoTinChi * 45,
                                            HeSoDiemQTHT = hocPhan.HocPhan.HeSoDiemQTHT,
                                            NgayBatDauDuKien = getNgayBatDauDuKien(hocKy, coSoDaoTao)
                                        };
                            #endregion
                            db.LopHocPhanDbSet.Add(lopHocPhan);
                            BizNhatKyHoatDong.LogAndCommitInsert2(lopHocPhan, lopHocPhan.MaLopHocPhanGUID, LOAIDOITUONG.LỚP_HỌC_PHẦN, db);

                            // Danh sách học viên cho lopHocPhan này
                            var lstHocVien = db.HocVienDbSet
                                .Where(e => e.MaLopKhoaNganhGUID == hocPhan.LopKhoaNganh.MaLopKhoaNganhGUID).ToList();

                            #region var lstMaHocVienDaDangKyHP = danh sách NaHocVien đã đăng ký học phần
                            var lstMaHocVienDaDangKyHP = db.LopHocPhan_HocVienDbSet.Include("LopHocPhan")
                                                    .Where(e => e.LopHocPhan.MaHocPhanGUID == hocPhan.MaHocPhanGUID)
                                                    .Select(e => e.MaHocVien)
                                                    .ToList();
                            lstMaHocVienDaDangKyHP.Sort();
                            #endregion

                            #region Bổ sung các học viên cần thiết vào lopHocPhan;
                            string ghiChu = string.Format("Đăng ký tự động vào lúc {0}", System.DateTime.Now.ToString("dd/MM/yyyy HH:mm"));
                            var nSoHocVienBoSung = 0;
                            var maLopHocPhanMoi = lopHocPhan.MaLopHocPhanGUID;
                            foreach (var hocVien in lstHocVien)
                            {
                                var lanHocHocPhanCuaHocVien = 1; // TODO: Tính lần học HocPhan này của học viên hocVien
                                bool hocVienHocThayThe = false;
                                string maHocPhanGUID_ThayThe = null;
                                if (lstMaHocVienDaDangKyHP.Contains(hocVien.MaHocVien) == false)
                                {
                                    nSoHocVienBoSung++;
                                    var recDangKyLHP = new LopHocPhan_HocVien()
                                    {
                                        MaLopHocPhanGUID = maLopHocPhanMoi,
                                        MaHocVien = hocVien.MaHocVien,
                                        LanHoc = lanHocHocPhanCuaHocVien,
                                        HocThayThe = hocVienHocThayThe,
                                        MaHocPhanGUID_ThayThe = maHocPhanGUID_ThayThe,
                                        GhiChu = ghiChu
                                    };
                                    db.LopHocPhan_HocVienDbSet.Add(recDangKyLHP);
                                    BizNhatKyHoatDong.LogAndCommitInsert2(recDangKyLHP, recDangKyLHP.MaHocVien, LOAIDOITUONG.LỚP_HỌC_PHẦN_HỌC_VIÊN, db);
                                }
                            }
                            //db.LopHocPhanDbSet.Add(lopHocPhan);
                            //BizNhatKyHoatDong.LogAndCommitInsert<LopHocPhan>(lopHocPhan, lopHocPhan.MaLopHocPhanGUID, LOAIDOITUONG.LỚP_HỌC_PHẦN, db);
                            #endregion
                            #endregion

                            lstAdded.Add(lopHocPhan);
                        }

                        //BizNhatKyHoatDong.LogAndCommitInsert<List<LopHocPhan>>(lstAdded, System.Guid.NewGuid().ToString(), LOAIDOITUONG.LỚP_HỌC_PHẦN, db);
                        trans.Commit();
                        return lstAdded.Count;
                    }
                    catch (Exception exc)
                    {
                        trans.Rollback();
                        throw exc;
                    }
                }
            }
        }
        #endregion

        /// <summary>
        /// Lấy danh sách các lớp học phần cùng tính chất (cùng học kỳ, cùng học phần, cùng khoá học) với 1 lớp học phần khác.
        /// </summary>
        /// <param name="lopHocPhan"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<LopHocPhan> GetListLopHocPhanCungKhoaHoc(LopHocPhan lopHocPhan, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetListLopHocPhanCungKhoaHoc(lopHocPhan, db2);
            else
            {
                var maHocKyGuid = lopHocPhan.MaHocKyGUID;
                var maHocPhanGuid = lopHocPhan.MaHocPhanGUID;
                var maLopHocPhanGuid = lopHocPhan.MaLopHocPhanGUID;
                var maLopKhoaNganhThamChieu = lopHocPhan.MaLopKhoaNganhThamChieu;
                var lopKhoaNganh = db.LopKhoaNganhDbSet
                    .Include("KhoaHoc_NganhDaoTao")
                    .Where(e => e.MaLopKhoaNganhGUID == maLopKhoaNganhThamChieu).FirstOrDefault();
                var maKhoaHocGuid = lopKhoaNganh.KhoaHoc_NganhDaoTao.MaKhoaHocGUID;
                var maCoSoDaoTaoGuid = lopKhoaNganh.MaCoSoDaoTaoGUID;

                var lstLopHocPhan = db.LopHocPhanDbSet
                    .Include("LopHocPhan_HocVien")
                    .Where(e => e.MaHocKyGUID == maHocKyGuid &&
                    e.MaHocPhanGUID == maHocPhanGuid &&
                    e.MaLopHocPhanGUID != maLopHocPhanGuid).ToList();
                for (int i = lstLopHocPhan.Count - 1; i >= 0; i--)
                {
                    var x = lstLopHocPhan[i];
                    // Xác định lớp khoá-ngành tham chiếu của x
                    LopKhoaNganh lopKhoaNganhX = db.LopKhoaNganhDbSet
                        .Include("KhoaHoc_NganhDaoTao")
                        .Where(e => e.MaLopKhoaNganhGUID == x.MaLopKhoaNganhThamChieu).FirstOrDefault();
                    if (lopKhoaNganhX.KhoaHoc_NganhDaoTao.MaKhoaHocGUID != maKhoaHocGuid ||
                        lopKhoaNganhX.MaCoSoDaoTaoGUID != maCoSoDaoTaoGuid)
                        lstLopHocPhan.RemoveAt(i);
                    x._LopKhoaNganhThamChieu = lopKhoaNganhX;
                }

                return lstLopHocPhan;
            }
        }

        /// <summary>
        /// Lấy danh sách học phần có thể thay thế cho học phần "hocPhan" của học viên "cuaHocVien"
        /// </summary>
        /// <param name="hocPhan"></param>
        /// <param name="cuaHocVien"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        internal static List<HocPhan> GetListHocPhanThayTheCho(HocPhan hocPhan, HocVien cuaHocVien, CEMS4UG_DHKHContext db = null)
        {
            if (db == null)
                using (var db2 = CEMS4UG_DHKHContext.GetContext())
                    return GetListHocPhanThayTheCho(hocPhan, cuaHocVien, db2);
            else
            {
                // 1. Tìm lớp khoá ngành của học viên
                var lopKhoaNganh = db.LopKhoaNganhDbSet
                    .Where(e => e.MaLopKhoaNganhGUID == cuaHocVien.MaLopKhoaNganhGUID).FirstOrDefault();
                if (lopKhoaNganh == null)
                    throw new Exception("Không xác định được lớp khoá-ngành của học viên");

                // 2. Tìm chương trình đào tạo của lớp khoá-ngành
                var maCTDT = db.KhoaHoc_NganhDaoTaoDbSet
                    .Where(e => e.MaDaoTaoKhoaNganhGUID == lopKhoaNganh.MaDaoTaoKhoaNganhGUID)
                    .Select(e => e.MaChuongTrinhDaoTaoGUID).FirstOrDefault();
                if (string.IsNullOrEmpty(maCTDT))
                    throw new Exception("Không xác định được chương trình đào tạo của học viên");

                // 3. Lấy về danh sách các học phần trong CTDT của lớp khoá-ngành
                var lstHocPhan = db.ChuongTrinhDaoTao_HocPhanDbSet.Include("HocPhan")
                    .Where(e => e.MaChuongTrinhDaoTaoGUID == maCTDT && e.MaHocPhan != hocPhan.MaHocPhanGUID)
                    .Select(e => e.HocPhan)
                    .ToList();
                return lstHocPhan;
            }
        }
    }
}
